﻿using Microsoft.TeamFoundation;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Client;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using TfsGetBuildDrop.Core.Exceptions;

namespace TfsGetBuildDrop.Core
{
    public class TfsProjectBuildManager
    {
        /// <summary>
        /// Complete url address for connect
        /// </summary>
        public string Address { get; set; }

        /// <summary>
        /// Project name
        /// </summary>
        public string Project { get; set; }

        /// <summary>
        /// The name of build definition
        /// </summary>
        public string BuildName { get; set; }

        TfsTeamProjectCollection collection;
        IBuildServer srvbuild;
        IBuildDefinition buildDef;
        string Username;
        string Password;

        public TfsProjectBuildManager()
        {

        }

        public string GetDisplayName()
        {
            return collection.DisplayName;
        }

        /// <summary>
        /// Retrive the last good build number
        /// </summary>
        /// <returns></returns>
        public string GetLastGoodBuildNumber()
        {
            var build = GetLstGoodBuild();
            if (build != null)
            {
                return build.BuildNumber;
            }
         
            return null;
        }

        /// <summary>
        /// Connect to the TFS build definition
        /// </summary>
        /// <param name="Address"></param>
        /// <param name="Project"></param>
        /// <param name="BuildName"></param>
        /// <param name="Username"></param>
        /// <param name="Password"></param>
        /// <returns></returns>
        public bool Connect(string Address, string Project, string BuildName, string Username = null, string Password = null)
        {
            this.Project = Project;
            this.BuildName = BuildName;
            this.Username = Username;
            this.Password = Password;

            try
            {
                TfsClientCredentials tfsCredential;
                if (Username == null)
                {
                    tfsCredential = new TfsClientCredentials(true);
                }
                else
                {
                    var networkCredential = new NetworkCredential(Username, Password);
                    tfsCredential = new TfsClientCredentials(new BasicAuthCredential(networkCredential));
                }

                collection = new TfsTeamProjectCollection(new Uri(Address), tfsCredential);
                this.srvbuild = collection.GetService<IBuildServer>();

                IBuildDefinition[] definitions = srvbuild.QueryBuildDefinitions(Project, QueryOptions.Definitions);

                this.buildDef = definitions.FirstOrDefault(s => StringComparer.OrdinalIgnoreCase.Equals(s.Name, BuildName));
                if (this.buildDef != null)
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                //TeamFoundationServerUnauthorizedException
                throw new TfsGetBuildDrop.Core.Exceptions.TfsProjectBuildManagerConnectException(ex.Message);
            }

            return false;
        }

        private IBuildDetail GetBuildByNumber(string BuildNumber)
        {
            IBuildDetail build = null;
            if (!string.IsNullOrEmpty(BuildNumber))
            {
                build = buildDef.QueryBuilds().FirstOrDefault(b => StringComparer.OrdinalIgnoreCase.Equals(b.BuildNumber, BuildNumber));
                if (build != null)
                {
                    return build;
                }
            }
            return null;
        }

        private IBuildDetail GetLstGoodBuild()
        {
            var buildUri = buildDef.LastGoodBuildUri;
            if (buildUri != null)
            {

                var build = srvbuild.GetBuild(buildUri);
                
                return build;
            }
            return null;
        }

        /// <summary>
        /// Retrive the download URL for the buil number 
        /// </summary>
        /// <param name="BuildNumber"></param>
        /// <returns></returns>
        public string GetDropDownloadUrl(string BuildNumber)
        {
            var build = GetBuildByNumber(BuildNumber);

            if (!string.IsNullOrEmpty(build.DropLocation))
            {
                return string.Format(CultureInfo.InvariantCulture, "{0}/{1}/_api/_build/ItemContent?buildUri={2}&path={3}", collection.Uri, Uri.EscapeUriString(build.TeamProject), Uri.EscapeUriString(build.Uri.ToString()),Uri.EscapeUriString("drop"));
            }

            return null;
        }

        public System.IO.MemoryStream DownloadDrop(string BuildNumber)
        {
            var path = GetDropDownloadUrl(BuildNumber);
            var uri = new Uri(path);
            var credentialCache = new CredentialCache();
            HttpClientHandler handler;

            if (string.IsNullOrEmpty(Username)) {
                handler = new HttpClientHandler();
                handler.UseDefaultCredentials = true;
            }else
                {
                credentialCache.Add(
                new Uri(uri.GetLeftPart(UriPartial.Authority)), "NTLM", new NetworkCredential(Username, Password));
                handler = new HttpClientHandler();
                handler.Credentials = credentialCache;
            }
         
                using (HttpClient httpClient = new HttpClient(handler))
                {
                    httpClient.Timeout = new TimeSpan(0, 30, 0);

                    System.IO.MemoryStream memStream = new System.IO.MemoryStream();
                    
                    HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(path));
                    request.Headers.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/zip"));

                    var response = httpClient.SendAsync(request).Result;
                    response.EnsureSuccessStatusCode();
                    response.Content.CopyToAsync(memStream).Wait();

                    return memStream;
                    
                }
            }
        
    }
}
